//
//  BudgetDao.swift
//  KoiAccounting
//
//  Created by 纪洪文 on 15.04.25.
//

import Foundation
import GRDB

class BudgetDao {
    let dbQueue: DatabaseQueue
    
    init(dbQueue: DatabaseQueue) {
        self.dbQueue = dbQueue
    }
    
    
    func save(budget: AccountingBudget?) {
        guard var budget = budget else { return }
        do {
            try dbQueue.write { db in
                try budget.insert(db, onConflict: .replace)
            }
        } catch {
            logger.error("save budget fail \(error)")
        }
    }
    
    func update(budget: AccountingBudget?) {
        guard var budget = budget else { return }
        budget.makeDelete()
        do {
            try dbQueue.write { db in
                try budget.update(db)
            }
        } catch {
            logger.error("update budget fail \(error)")
        }
    }
    
    func get(uid: String, bookId: String, budgetId: String) -> AccountingBudget? {
        do {
            return try dbQueue.read { db in
                try AccountingBudget
                    .filter(AccountingBudget.Columns.uid == uid)
                    .filter(AccountingBudget.Columns.bookId == bookId)
                    .filter(AccountingBudget.Columns.budgetId == budgetId)
                    .fetchOne(db)
            }
        } catch {
            logger.error("save budget fail \(error)")
        }
        return nil
    }
    
    func getBudgetTotal(uid: String, bookId: String) -> AccountingBudget? {
        do {
            return try dbQueue.read { db in
                return try AccountingBudget
                    .filter(AccountingBudget.Columns.uid == uid)
                    .filter(AccountingBudget.Columns.bookId == bookId)
                    .filter(AccountingBudget.Columns.isTotal == 1)
                    .filter(AccountingBudget.Columns.isDel == 0)
                    .fetchOne(db)
            }
        } catch {
            logger.error("getBudgetTotal \(error)")
        }
        return nil
    }
    
    func getBudgetTotalAmount(uid: String, bookId: String) -> Double {
        var totalAmount: Double?
        do {
            totalAmount = try dbQueue.read { db in
                return try Double.fetchOne(db, sql: "select amount from accounting_budget where uid = ? and book_id = ? and is_total = 1 and is_del <>1", arguments: [uid, bookId])
            }
        } catch {
            logger.error("getBudgetTotal \(error)")
        }
        return totalAmount ?? 0.0
    }
    
    func getBudgetCategoryTotal(uid: String, bookId: String) -> Double {
        var totalAmount: Double?
        do {
            totalAmount = try dbQueue.read { db in
                return try Double.fetchOne(db, sql: "select sum(amount) from accounting_budget where uid = ? and book_id = ? and is_total <> 1 and is_del <>1", arguments: [uid, bookId])
            }
        } catch {
            logger.error("getBudgetTotal \(error)")
        }
        return totalAmount ?? 0.0
    }
    
    func getBudgetCategoryAmount(uid: String, bookId: String, cid: String) -> Double {
        var totalAmount: Double?
        do {
            totalAmount = try dbQueue.read { db in
                return try Double.fetchOne(db, sql: "select sum(amount) from accounting_budget where uid = ? and book_id = ? and cid = ? and is_total <> 1 and is_del <>1", arguments: [uid, bookId, cid])
            }
        } catch {
            logger.error("getBudgetTotal \(error)")
        }
        return totalAmount ?? 0.0
    }
    
    func getBudgerCategoryList(uid: String, bookId: String) -> [AccountingBudget] {
        do {
            return try dbQueue.read { db in
                return try AccountingBudget
                    .filter(AccountingBudget.Columns.uid == uid)
                    .filter(AccountingBudget.Columns.bookId == bookId)
                    .filter(AccountingBudget.Columns.isTotal != 1)
                    .filter(AccountingBudget.Columns.isDel != 1)
                    .fetchAll(db)
            }
        } catch {
            logger.error("getBudgerCategoryList \(error)")
        }
        return [AccountingBudget]()
    }
    
    func getAll(uid: String, bookId: String) -> Array<AccountingBudget> {
        do {
            return try dbQueue.read { db in
                return try AccountingBudget
                    .filter(AccountingBudget.Columns.uid == uid)
                    .filter(AccountingBudget.Columns.bookId == bookId)
                    .filter(AccountingBudget.Columns.isDel != 1)
                    .fetchAll(db)
            }
        } catch {
            logger.error("getBudgerCategoryList \(error)")
        }
        return [AccountingBudget]()
    }
    
    func update(list: Array<AccountingBudget>) throws {
        try dbQueue.write { db in
            try list.forEach { item in
                var item = item
                item.makeDelete()
                try item.update(db)
            }
        }
    }
}
